/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package Wires.impl;

import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.m2m.atl.engine.AtlEMFModelHandler;
import org.eclipse.m2m.atl.engine.vm.nativelib.ASMModel;

import Wires.AtomicModelTransformation;
import Wires.BasicData;
import Wires.CompositeTransformation;
import Wires.ConnectableElement;
import Wires.DataFlow;
import Wires.GenericTransformation;
import Wires.IdentityTransformation;
import Wires.Model;
import Wires.OutputActualParameter;
import Wires.OutputFormalParameter;
import Wires.WiresPackage;
import Wires.exep.ResourceNotFoundException;
import Wires.exep.TypeNotFoundException;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Output Formal Parameter</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * </p>
 *
 * @generated
 */
public class OutputFormalParameterImpl extends FormalParameterImpl implements OutputFormalParameter {
	/***************************************************/
	/***************** Modifications *******************/
	
	OutputActualParameter actualParameter;
			
	public void loadModel(){
		String modelName = this.getName();
		AtlEMFModelHandler modelHandler = (AtlEMFModelHandler) AtlEMFModelHandler.getDefault(AtlEMFModelHandler.AMH_EMF);
		this.model =  modelHandler.loadModel(modelName, this.metamodel, URI.createFileURI(this.modelPath));
	}

	public void execute(ConnectableElement incoming) throws Exception{				
		//Prepare the parameter with the incoming data
		if (incoming instanceof Model){
			
			if (((Model)incoming).getPath() == null)
				throw new TypeNotFoundException(incoming);
			
			//Save the model path
			this.modelPath = ((Model)incoming).getPath();
			
			File f = new File(modelPath);
			if (!f.exists()) {
				throw new ResourceNotFoundException(incoming);
			}
			
			//Load the model
			this.loadMetamodel();
			this.loadModel();

		}else if (incoming instanceof BasicData){
			//Store the basic value of the BasicData
			this.setBasicDataValue(((BasicDataImpl)incoming).getValue());
			
		}else if (incoming instanceof OutputActualParameter){
			if (((OutputActualParameter) incoming).eContainer() instanceof IdentityTransformation){				
				//Copy the model path of the incoming OutputParameter
				this.setModelPath(((OutputActualParameterImpl)incoming).getModelPath());
				
				if (this.getPath() != null && !this.getPath().equals("")){					
					this.loadMetamodel();
					this.loadModel();					
					AtlEMFModelHandler modelHandler = (AtlEMFModelHandler) AtlEMFModelHandler.getDefault(AtlEMFModelHandler.AMH_EMF);
					modelHandler.saveModel(model, this.getPath(), false);
				}
			}else if (((OutputActualParameter) incoming).eContainer() instanceof AtomicModelTransformation ||
				((OutputActualParameter) incoming).eContainer() instanceof GenericTransformation){
				
				this.copyASMModel(((OutputActualParameterImpl)incoming).getModel());
								
			}else if (((OutputActualParameter) incoming).eContainer() instanceof CompositeTransformation){				
				//Check if the incoming OutputParameter contains a BasicData or a model
				if (((OutputActualParameterImpl)incoming).basicDataValue == null){
					//The incoming parameter contains a Model
					this.copyASMModel(((OutputActualParameterImpl)incoming).getModel());
				}else{
					//The incoming parameter contains a BasicData
					this.setBasicDataValue(((OutputActualParameterImpl)incoming).getBasicDataValue());
				}
			}else if (((OutputActualParameter) incoming).eContainer() instanceof QueryImpl
					|| ((OutputActualParameter) incoming).eContainer() instanceof Model2TextTransformationTypeImpl){				
				this.setBasicDataValue(((OutputActualParameterImpl)incoming).getBasicDataValue());
			}
		}
		
		if (this.getPath() == null || this.getPath().equals("")){
			((ActualParameterImpl)actualParameter).basicDataValue = this.basicDataValue;
			((ActualParameterImpl)actualParameter).metamodel = this.metamodel;
			((ActualParameterImpl)actualParameter).model = this.model;
			((ActualParameterImpl)actualParameter).modelPath = this.modelPath;
			
			List<ConnectableElement> outgoingElements = new LinkedList<ConnectableElement>();
			for (DataFlow f : actualParameter.getOutgoing()){
				outgoingElements.add(f.getTarget());
			}
			
			WiresSpecificationImpl.execute(outgoingElements,actualParameter);
		}else{
			if (this.model!=null){
				AtlEMFModelHandler modelHandler = (AtlEMFModelHandler) AtlEMFModelHandler.getDefault(AtlEMFModelHandler.AMH_EMF);
				modelHandler.saveModel(this.model, this.getPath(), false);
			}else if (this.basicDataValue!=null){
				if (((OutputActualParameter) incoming).eContainer() instanceof Model2TextTransformationImpl){
					// Remove simple Quote (') at the beginning and the end
					BasicDataImpl.writeValueToFile(this.basicDataValue.toString().substring(1, this.basicDataValue.toString().length()-1), this.getPath());
				}else{
					BasicDataImpl.writeValueToFile(this.basicDataValue.toString(), this.getPath());
				}
				
			}		
		}		
	}
	
	private void copyASMModel(ASMModel model){
		//Copy the out parameter model on this input parameter
//		AtlEMFModelHandler modelHandler = (AtlEMFModelHandler) AtlEMFModelHandler.getDefault(AtlEMFModelHandler.AMH_EMF);
//		modelHandler.saveModel(model, model.getName(), false);
//		this.modelPath = model.getName();	
		
		String name = "tmp" + UUID.randomUUID().toString();
		AtlEMFModelHandler modelHandler = (AtlEMFModelHandler)AtlEMFModelHandler.getDefault("EMF");
		modelHandler.saveModel(model, name, false);
		this.modelPath = name;

		
		this.loadMetamodel();
		this.loadModel();		
		
//		File f = new File(model.getName());
		File f = new File(name);
		f.delete();
	}
	
	/**************** Modifications End ****************/
	/***************************************************/
	
	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected OutputFormalParameterImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return WiresPackage.Literals.OUTPUT_FORMAL_PARAMETER;
	}

} //OutputFormalParameterImpl
